﻿using Serilog;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace SD.App.Desktop.Repository
{
    /// <summary>
    /// 通用 Repository 基类（SqlSugar 实现，低版本兼容）
    /// </summary>
    /// <typeparam name="T">实体类</typeparam>
    /// <typeparam name="TKey">主键类型</typeparam>
    public class BaseRepository<T, TKey> : IRepository<T, TKey> , IScopedLifetime where T : class, new()
    {
        // BaseRepository 中添加静态缓存字典
        private static readonly Dictionary<Type, string> _primaryKeyCache = new Dictionary<Type, string>();

        // 新增缓存：主键是否为 Identity 缓存（键：实体类型，值：是否自增）
        private static readonly Dictionary<Type, bool> _isIdentityCache = new();

        /// <summary>
        /// SqlSugar 客户端（从上下文注入）
        /// </summary>
        protected readonly ISqlSugarClient _dbClient;

        /// <summary>
        /// 日志对象
        /// </summary>
        protected readonly ILogger _logger;

        /// <summary>
        /// 实体对应的数据库表名（从实体类 SugarTable 注解获取）
        /// </summary>
        protected readonly string _tableName;

        /// <summary>
        /// 构造函数（注入 SqlSugarContext 和 Logger）
        /// </summary>
        public BaseRepository(SqlSugarContext sqlSugarContext, ILogger logger)
        {
            _dbClient = sqlSugarContext.Client;
            _logger = logger;
            _tableName = _dbClient.EntityMaintenance.GetTableName<T>(); // 获取实体对应的表名
            _logger.Debug("初始化通用 Repository：表名={TableName}", _tableName);
        }

        #region 新增
        public async Task<T> AddAsync(T entity)
        {
            try
            {
                _logger.Debug("新增数据：表名={TableName}", _tableName);

                // 可根据 Identity 类型调整新增逻辑（示例：自增主键无需手动赋值）
                if (IsPrimaryKeyIdentity())
                {
                    var primaryKeyName = GetPrimaryKeyNameByReflection();
                    var primaryKeyProp = typeof(T).GetProperty(primaryKeyName);
                    // 清空主键值（避免手动赋值导致自增异常）
                    primaryKeyProp?.SetValue(entity, default(TKey));
                    _logger.Debug("主键为自增类型，清空手动赋值：{PrimaryKeyName}", primaryKeyName);
                }

                return await _dbClient.Insertable(entity).ExecuteReturnEntityAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "新增数据失败：表名={TableName}", _tableName);
                throw;
            }
        }

        public async Task<int> BatchAddAsync(List<T> entities)
        {
            if (entities == null || entities.Count == 0)
            {
                _logger.Warning("批量新增数据为空：表名={TableName}", _tableName);
                return 0;
            }

            try
            {
                _logger.Debug("批量新增数据：表名={TableName}，条数={Count}", _tableName, entities.Count);
                return await _dbClient.Insertable(entities).ExecuteCommandAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "批量新增数据失败：表名={TableName}", _tableName);
                throw;
            }
        }
        #endregion

        #region 删除
        public async Task<int> DeleteByIdAsync(TKey id)
        {
            try
            {
                _logger.Debug("根据主键删除数据：表名={TableName}，主键={Id}", _tableName, id);
                return await _dbClient.Deleteable<T>().In(id).ExecuteCommandAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "根据主键删除数据失败：表名={TableName}，主键={Id}", _tableName, id);
                throw;
            }
        }

        public async Task<int> BatchDeleteByIdsAsync(List<TKey> ids)
        {
            if (ids == null || ids.Count == 0)
            {
                _logger.Warning("批量删除主键为空：表名={TableName}", _tableName);
                return 0;
            }

            try
            {
                _logger.Debug("批量删除数据：表名={TableName}，主键条数={Count}", _tableName, ids.Count);
                return await _dbClient.Deleteable<T>().In(ids).ExecuteCommandAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "批量删除数据失败：表名={TableName}", _tableName);
                throw;
            }
        }

        public async Task<int> DeleteByConditionAsync(Expression<Func<T, bool>> whereExpression)
        {
            try
            {
                _logger.Debug("根据条件删除数据：表名={TableName}", _tableName);
                return await _dbClient.Deleteable<T>().Where(whereExpression).ExecuteCommandAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "根据条件删除数据失败：表名={TableName}", _tableName);
                throw;
            }
        }
        #endregion

        #region 修改
        public async Task<int> UpdateAsync(T entity)
        {
            try
            {
                _logger.Debug("全量更新数据：表名={TableName}", _tableName);
                return await _dbClient.Updateable(entity).ExecuteCommandAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "全量更新数据失败：表名={TableName}", _tableName);
                throw;
            }
        }

        public async Task<int> BatchUpdateAsync(List<T> entities)
        {
            if (entities == null || entities.Count == 0)
            {
                _logger.Warning("批量更新数据为空：表名={TableName}", _tableName);
                return 0;
            }

            try
            {
                _logger.Debug("批量全量更新数据：表名={TableName}，条数={Count}", _tableName, entities.Count);
                return await _dbClient.Updateable(entities).ExecuteCommandAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "批量全量更新数据失败：表名={TableName}", _tableName);
                throw;
            }
        }

        public async Task<int> UpdatePartialAsync(T entity, Expression<Func<T, object>> updateColumns)
        {
            try
            {
                _logger.Debug("按需更新数据：表名={TableName}", _tableName);
                // 只更新指定字段（低版本支持 UpdateColumns 方法）
                return await _dbClient.Updateable(entity)
                                     .UpdateColumns(updateColumns)
                                     .ExecuteCommandAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "按需更新数据失败：表名={TableName}", _tableName);
                throw;
            }
        }

        public async Task<int> UpdateByConditionAsync(Expression<Func<T, bool>> whereExpression, Expression<Func<T, T>> updateExpression)
        {
            try
            {
                _logger.Debug("按条件更新数据：表名={TableName}", _tableName);
                return await _dbClient.Updateable<T>()
                                     .SetColumns(updateExpression)
                                     .Where(whereExpression)
                                     .ExecuteCommandAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "按条件更新数据失败：表名={TableName}", _tableName);
                throw;
            }
        }
        #endregion

        #region 查询
        public async Task<T?> GetByIdAsync(TKey id)
        {
            try
            {
                _logger.Debug("根据主键查询数据：表名={TableName}，主键={Id}", _tableName, id);
                // 低版本无 FirstAsync，用 FirstOrDefault 替代（返回 null 无数据）
                return await _dbClient.Queryable<T>().In(id).FirstAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "根据主键查询数据失败：表名={TableName}，主键={Id}", _tableName, id);
                throw;
            }
        }

        public async Task<T?> GetFirstAsync(Expression<Func<T, bool>> whereExpression)
        {
            try
            {
                _logger.Debug("根据条件查询第一条数据：表名={TableName}", _tableName);
                return await _dbClient.Queryable<T>()
                                     .Where(whereExpression)
                                     .FirstAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "根据条件查询第一条数据失败：表名={TableName}", _tableName);
                throw;
            }
        }

        public async Task<List<T>> GetAllAsync()
        {
            try
            {
                _logger.Debug("查询所有数据：表名={TableName}", _tableName);
                return await _dbClient.Queryable<T>().ToListAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "查询所有数据失败：表名={TableName}", _tableName);
                throw;
            }
        }

        public async Task<List<T>> GetListAsync(Expression<Func<T, bool>>? whereExpression = null)
        {
            try
            {
                var query = _dbClient.Queryable<T>();
                if (whereExpression != null)
                {
                    query = query.Where(whereExpression);
                }
                _logger.Debug("根据条件查询数据列表：表名={TableName}", _tableName);
                return await query.ToListAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "根据条件查询数据列表失败：表名={TableName}", _tableName);
                throw;
            }
        }

        public async Task<List<T>> GetListOrderByAsync(Expression<Func<T, bool>>? whereExpression = null,
            Expression<Func<T, object>>? orderExpression = null, bool isAsc = true)
        {
            try
            {
                var query = _dbClient.Queryable<T>();
                // 条件过滤
                if (whereExpression != null)
                {
                    query = query.Where(whereExpression);
                }
                // 排序（低版本支持 OrderBy/OrderByDescending）
                if (orderExpression != null)
                {
                    query = isAsc ? query.OrderBy(orderExpression) : query.OrderByDescending(orderExpression);
                }
                _logger.Debug("条件+排序查询数据列表：表名={TableName}", _tableName);
                return await query.ToListAsync();
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "条件+排序查询数据列表失败：表名={TableName}", _tableName);
                throw;
            }
        }

        public async Task<(List<T> Data, int TotalCount)> GetPageListAsync(int pageIndex, int pageSize,
            Expression<Func<T, bool>>? whereExpression = null)
        {
            return await GetPageListOrderByAsync(pageIndex, pageSize, whereExpression, null);
        }

        public async Task<(List<T> Data, int TotalCount)> GetPageListOrderByAsync(int pageIndex, int pageSize,
            Expression<Func<T, bool>>? whereExpression = null,
            Expression<Func<T, object>>? orderExpression = null, bool isAsc = true)
        {
            if (pageIndex < 1) pageIndex = 1;
            if (pageSize < 1) pageSize = 10;

            try
            {
                var query = _dbClient.Queryable<T>();
                // 条件过滤
                if (whereExpression != null)
                {
                    query = query.Where(whereExpression);
                }
                // 排序（无排序表达式时，按主键排序，避免分页混乱）
                if (orderExpression != null)
                {
                    query = isAsc ? query.OrderBy(orderExpression) : query.OrderByDescending(orderExpression);
                }
                else
                {
                    // 获取主键字段（低版本通过实体注解获取）
                    var primaryKey = GetPrimaryKeyNameByReflection();
                    if (primaryKey != null)
                    {
                        query = query.OrderBy($"{primaryKey}");
                    }
                }

                // 低版本分页：先查总条数，再查当前页数据
                int totalCount = await query.CountAsync();
                var data = await query.Skip((pageIndex - 1) * pageSize)
                                     .Take(pageSize)
                                     .ToListAsync();

                _logger.Debug("分页查询：表名={TableName}，页码={PageIndex}，每页条数={PageSize}，总条数={TotalCount}",
                    _tableName, pageIndex, pageSize, totalCount);
                return (data, totalCount);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "分页查询失败：表名={TableName}，页码={PageIndex}，每页条数={PageSize}",
                    _tableName, pageIndex, pageSize);
                throw;
            }
        }

        public async Task<bool> ExistsAsync(Expression<Func<T, bool>> whereExpression)
        {
            try
            {
                // 低版本无 AnyAsync，用 CountAsync > 0 替代
                int count = await _dbClient.Queryable<T>()
                                         .Where(whereExpression)
                                         .CountAsync();
                bool exists = count > 0;
                _logger.Debug("检查数据是否存在：表名={TableName}，结果={Exists}", _tableName, exists);
                return exists;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "检查数据是否存在失败：表名={TableName}", _tableName);
                throw;
            }
        }

        public async Task<int> CountAsync(Expression<Func<T, bool>>? whereExpression = null)
        {
            try
            {
                var query = _dbClient.Queryable<T>();
                if (whereExpression != null)
                {
                    query = query.Where(whereExpression);
                }
                int count = await query.CountAsync();
                _logger.Debug("统计数据条数：表名={TableName}，条数={Count}", _tableName, count);
                return count;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "统计数据条数失败：表名={TableName}", _tableName);
                throw;
            }
        }
        #endregion

        #region 低版本兼容：反射获取主键字段名（替代 GetPrimaryKey<T>()）
        /// <summary>
        /// 通过反射读取实体类的主键字段名（解析 [SugarColumn(IsPrimaryKey = true)] 注解）
        /// </summary>
        private string GetPrimaryKeyNameByReflection()
        {
            // 先从缓存获取，避免重复反射
            if (_primaryKeyCache.TryGetValue(typeof(T), out var cachedPkName))
            {
                return cachedPkName;
            }

            try
            {
                PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
                foreach (var prop in properties)
                {
                    var sugarColumnAttr = prop.GetCustomAttribute<SugarColumn>();
                    if (sugarColumnAttr != null && sugarColumnAttr.IsPrimaryKey)
                    {
                        _primaryKeyCache[typeof(T)] = prop.Name; // 存入缓存
                        return prop.Name;
                    }
                }

                // 约定 fallback
                var idProp = properties.FirstOrDefault(p => p.Name.Equals("Id", StringComparison.OrdinalIgnoreCase));
                string pkName = idProp?.Name ?? string.Empty;
                _primaryKeyCache[typeof(T)] = pkName; // 缓存约定主键
                return pkName;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "反射获取实体 {EntityName} 主键失败", typeof(T).Name);
                _primaryKeyCache[typeof(T)] = string.Empty; // 缓存失败结果
                return string.Empty;
            }
        }
        #endregion

        #region 核心功能：判断主键是否为 Identity（自增）类型
        /// <summary>
        /// 判断当前实体的主键是否为 Identity（自增）类型
        /// </summary>
        /// <returns>true：自增；false：非自增（如手动赋值、UUID等）</returns>
        private bool IsPrimaryKeyIdentity()
        {
            // 先从缓存获取，避免重复反射
            if (_isIdentityCache.TryGetValue(typeof(T), out bool isIdentity))
            {
                return isIdentity;
            }

            try
            {
                // 1. 获取主键字段（复用之前的反射逻辑）
                string primaryKeyName = GetPrimaryKeyNameByReflection();
                if (string.IsNullOrEmpty(primaryKeyName))
                {
                    _logger.Warning("实体 {EntityName} 未找到主键，无法判断是否为 Identity", typeof(T).Name);
                    _isIdentityCache[typeof(T)] = false; // 无主键默认非自增
                    return false;
                }

                // 2. 反射获取主键字段的 [SugarColumn] 注解
                var primaryKeyProp = typeof(T).GetProperty(primaryKeyName, BindingFlags.Public | BindingFlags.Instance);
                if (primaryKeyProp == null)
                {
                    _logger.Warning("实体 {EntityName} 主键字段 {PrimaryKeyName} 不存在", typeof(T).Name, primaryKeyName);
                    _isIdentityCache[typeof(T)] = false;
                    return false;
                }

                // 3. 读取注解的 IsIdentity 属性（低版本 SqlSugar 支持该属性）
                var sugarColumnAttr = primaryKeyProp.GetCustomAttribute<SugarColumn>();
                isIdentity = sugarColumnAttr != null && sugarColumnAttr.IsIdentity;

                // 4. 存入缓存（后续直接复用）
                _isIdentityCache[typeof(T)] = isIdentity;
                _logger.Debug("实体 {EntityName} 主键 {PrimaryKeyName} 是否自增：{IsIdentity}",
                    typeof(T).Name, primaryKeyName, isIdentity);

                return isIdentity;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "判断实体 {EntityName} 主键是否为 Identity 失败", typeof(T).Name);
                _isIdentityCache[typeof(T)] = false; // 异常默认非自增
                return false;
            }
        }
        #endregion
    }
}
